<script setup lang="ts">
import { throttle } from "lodash-es"
import { computed, reactive, ref, unref } from "vue"
import VuePdfEmbed from "vue-pdf-embed"

import { transformPdfUrlToBlobData } from "@/api/file"
import { useResetReactive } from "@/hooks/useReset"
import { blobToBase64string } from "@/utils/file"
import { Shape, ViewLoadType, ViewToolsOperate } from "./types"

// #region 预览简历
const pdfRenderViewRef = ref()
const pdfRef = ref()
const [pdfOpts, resetPdfOpts] = useResetReactive({
  source: "",
  total: 0, // 总页数
  current: 1,
  realHeight: 800, // 预览pdf文件宽度
  realWidth: 0,
  ratio: 1, // 实际页面和视口的比例
  scale: "1:1",
  shape: {
    width: 0,
    height: 0
  } as Shape,
  loading: ViewLoadType.No,
  loadProgress: 0
})

const pdfStyles = computed(() => {
  return {
    scale: Number(pdfOpts.scale.split(":")[1])
  }
})
const viewportShape = reactive<Shape>({
  width: document.documentElement.clientWidth,
  height: document.documentElement.clientHeight
})
const showResumeFile = ref<boolean>(false)
const toggleResumeFileVisible = (state?: boolean) => {
  showResumeFile.value = state ?? !unref(showResumeFile)
}
const handleLoaded = (pdf: any) => (pdfOpts.total = pdf._pdfInfo.numPages)
const handleCloseView = () => {
  resetPdfOpts()
  toggleResumeFileVisible(false)
}
const jumpPage = ({ step, page }: { step?: number; page?: number }) => {
  if (step && page) return
  if (!step && !page) return
  if (step) {
    return throttle(
      () => {
        if (step < 0 && pdfOpts.current > 1) pdfOpts.current = Math.min(pdfOpts.current + step, 1)
        if (step > 0 && pdfOpts.current < pdfOpts.total)
          pdfOpts.current = Math.max(pdfOpts.current + step, pdfOpts.total)
      },
      200,
      {
        leading: true
      }
    )
  }
  if (page) {
    if (page && page > 0 && page <= pdfOpts.total) {
      pdfOpts.current = page
    }
  }
}

async function handleOpenResumePdf(url: string) {
  if (showResumeFile.value === true) return
  toggleResumeFileVisible(true)
  const fileBlob = await transformPdfUrlToBlobData(url)
  pdfOpts.source = await blobToBase64string(fileBlob)
}

function handleRendered() {
  const initWidth = () => {
    const { offsetWidth: width, offsetHeight: height } = pdfRenderViewRef.value!.children[0] as HTMLElement
    pdfOpts.shape = {
      width,
      height
    }
    pdfOpts.ratio = Number(Math.min(viewportShape.width / width, viewportShape.height / height).toFixed(2))
    pdfOpts.realWidth = Math.round(width * pdfOpts.ratio)
    pdfOpts.realHeight = Math.round(height * pdfOpts.ratio)
  }

  initWidth()
  pdfOpts.loading = ViewLoadType.Finish
}

function handleViewToolsClick(type: ViewToolsOperate) {
  let realScale = Number(unref(pdfOpts.scale).split(":")[1])
  switch (type) {
    case ViewToolsOperate.LastPage:
      jumpPage({ step: -1 })
      break
    case ViewToolsOperate.NextPage:
      jumpPage({ step: 1 })
      break
    case ViewToolsOperate.ZoomOut:
      if (realScale < 2) {
        realScale += 0.1
        pdfOpts.scale = `1:${realScale.toFixed(1)}`
      }
      break
    case ViewToolsOperate.ZoomIn:
      if (realScale > 1) {
        realScale -= 0.1
        pdfOpts.scale = `1:${realScale.toFixed(1)}`
      }
      break
    default:
      return type as never
  }
}

defineExpose({
  handleOpenResumePdf
})
// #endregion
</script>

<template>
  <div id="pdf-viewer" v-if="showResumeFile" @click.stop.self="handleCloseView">
    <div ref="pdfRenderViewRef" class="render-view">
      <vue-pdf-embed
        ref="pdfRef"
        class="render-view-content"
        v-model:source="pdfOpts.source"
        :height="pdfOpts.realHeight"
        :width="pdfOpts.realWidth"
        :page="pdfOpts.current"
        @loaded="handleLoaded"
        @rendered="handleRendered"
      />
      <el-row
        :gutter="10"
        v-if="pdfOpts.loading === ViewLoadType.Finish"
        justify="center"
        align="middle"
        class="render-view-tools"
      >
        <el-col :span="8">
          <el-input-number
            v-model="pdfOpts.current"
            :min="1"
            :max="pdfOpts.total"
            :value-on-clear="1"
            :precision="0"
            step-strictly
          >
            <template #decrease-icon>
              <el-icon @click="handleViewToolsClick(ViewToolsOperate.LastPage)"><ArrowLeftBold /></el-icon>
            </template>
            <template #increase-icon>
              <el-icon @click="handleViewToolsClick(ViewToolsOperate.NextPage)"><ArrowRightBold /></el-icon>
            </template>
            <template #suffix>
              <span>/{{ pdfOpts.total }}</span>
            </template>
          </el-input-number>
        </el-col>
        <el-col :span="4" class="render-view-tools-item" @click="handleViewToolsClick(ViewToolsOperate.ZoomOut)">
          <svg-icon name="zoomOut" />
        </el-col>
        <el-col :span="4" class="render-view-tools-item" @click="handleViewToolsClick(ViewToolsOperate.ZoomIn)">
          <svg-icon name="zoomIn" />
        </el-col>
        <el-col :span="4" class="render-view-tools-item">
          <svg-icon name="zoomRatio" />
          <span>{{ pdfOpts.scale }}</span>
        </el-col>
      </el-row>
    </div>
  </div>
</template>

<style scoped lang="scss" src="./style.scss"></style>
<style scoped lang="scss">
.render-view-content {
  transform: scale(v-bind("pdfStyles.scale"));
}
</style>
